#include "systemc.h"
#include "random.h"
#include "channel.h"

#define INSTR_OPCODE instr.range(31,26)
#define INSTR_OFFSET instr.range(15,0)
#define INSTR_ADDRESS instr.range(19,0)

SC_MODULE(fetch)
{
// ------------in-out---------------------------------------------------------//
	sc_port< async_channel_out_if< sc_uint<32> > > imem_address;
	sc_port< async_channel_in_if< sc_uint<32> > > imem_data;
	sc_port< async_channel_out_if< sc_uint<32> > > fede_instruction;
	sc_port< async_channel_in_if< sc_uint<1> > > exfe_branch_decision;
//----------------------------------------------------------------------------//

//-------------Variáveis-Locais-----------------------------------------------//
	sc_uint<32> pc;
	sc_uint<32> instr;
	sc_uint<1> branch_decision;
	sc_uint<32> branch_offset;
//----------------------------------------------------------------------------//

	void behavior()
	{
		pc = 0;

		while(true)
		{
			imem_address->write(pc);
			imem_data->read(instr);

			pc++;

			switch(INSTR_OPCODE)
			{
				case 0x4: //BEQ
					fede_instruction->write(instr);
					exfe_branch_decision->read(branch_decision);

					if(branch_decision)
					{
						if(instr[15] == 1)
							branch_offset.range(31,16) = 0xFFFF;
						else
							branch_offset.range(31,16) = 0x0000;
						branch_offset(15,0) = INSTR_OFFSET;
						pc += branch_offset;
					}
					break;

				case 0x2: //J
					pc = (pc.range(31,20), INSTR_ADDRESS);
					break;

				default:
					fede_instruction->write(instr);
			}
		}
	}

	SC_CTOR(fetch)
	{
		SC_THREAD(behavior);
	}
};